Consider details for size-request and expose-event. (#339540)
authorMathias Hasselmann <hasselmm@src.gnome.org>
Fri, 28 Dec 2007 09:26:20 +0000 (09:26 +0000)
committerMathias Hasselmann <hasselmm@src.gnome.org>
Fri, 28 Dec 2007 09:26:20 +0000 (09:26 +0000)
* gtk/gtkcalendar.c: Add gtk_calendar_get_detail and
is_color_attribute functions. Change gtk_calendar_size_request
and calendar_paint_day to consider and show calender details.

svn path=/trunk/; revision=19261

ChangeLog
gtk/gtkcalendar.c

index 30b4ee37ada5df9ad406c1cf9a3a6057f242986e..feb0dddc3350d7b79d3b9d50dde78848829bb846 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-12-28  Mathias Hasselmann  <mathias@openismus.com>
+
+       Consider details for size-request and expose-event. (#339540)
+
+       * gtk/gtkcalendar.c: Add gtk_calendar_get_detail and
+       is_color_attribute functions. Change gtk_calendar_size_request
+       and calendar_paint_day to consider and show calender details.
+
 2007-12-28  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkcombobox.c: Introduce local priv variables to 
index 315713d2d8719d9a1316344c571a41f7cc538941..a1ee71219f8d6807015d9414d25bb68fb5e4f104 100644 (file)
@@ -255,6 +255,7 @@ struct _GtkCalendarPrivate
   guint             arrow_width;
   guint             max_month_width;
   guint             max_year_width;
+  guint             max_detail_height;
   
   guint day_width;
   guint week_width;
@@ -1602,6 +1603,34 @@ gtk_calendar_unrealize (GtkWidget *widget)
     (* GTK_WIDGET_CLASS (gtk_calendar_parent_class)->unrealize) (widget);
 }
 
+static G_CONST_RETURN gchar*
+gtk_calendar_get_detail (GtkCalendar *calendar,
+                         gint         row,
+                         gint         column)
+{
+  GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
+  gint year, month;
+
+  year = calendar->year;
+  month = calendar->month + calendar->day_month[row][column] - MONTH_CURRENT;
+
+  if (month < 0)
+    {
+      month += 12;
+      year -= 1;
+    }
+  else if (month > 11)
+    {
+      month -= 12;
+      year += 1;
+    }
+
+  return priv->detail_func (calendar,
+                            year, month,
+                            calendar->day[row][column],
+                            priv->detail_func_user_data);
+}
+
 \f
 /****************************************
  *       Size Request and Allocate      *
@@ -1617,7 +1646,7 @@ gtk_calendar_size_request (GtkWidget        *widget,
   PangoRectangle logical_rect;
 
   gint height;
-  gint i;
+  gint i, r, c;
   gint calendar_margin = CALENDAR_MARGIN;
   gint header_width, main_width;
   gint max_header_height = 0;
@@ -1700,8 +1729,6 @@ gtk_calendar_size_request (GtkWidget        *widget,
       priv->max_day_char_descent = MAX (priv->max_day_char_descent, 
                                                PANGO_DESCENT (logical_rect));
     }
-  /* We add one to max_day_char_width to be able to make the marked day "bold" */
-  priv->max_day_char_width = priv->min_day_width / 2 + 1;
   
   priv->max_label_char_ascent = 0;
   priv->max_label_char_descent = 0;
@@ -1730,6 +1757,77 @@ gtk_calendar_size_request (GtkWidget       *widget,
                                           logical_rect.width / 2);
       }
   
+  /* Calculate detail extents. Do this as late as possible since
+   * pango_layout_set_markup is called which alters font settings. */
+  priv->max_detail_height = 0;
+
+  if (priv->detail_func)
+    {
+      gchar *markup, *tail;
+
+      if (priv->detail_width_chars || priv->detail_height_rows)
+        {
+          gint rows = MAX (1, priv->detail_height_rows) - 1;
+          gsize len = priv->detail_width_chars + rows + 16;
+
+          markup = tail = g_alloca (len);
+
+          memcpy (tail,     "<small>", 7);
+          tail += 7;
+
+          memset (tail, 'm', priv->detail_width_chars);
+          tail += priv->detail_width_chars;
+
+          memset (tail, '\n', rows);
+          tail += rows;
+
+          memcpy (tail,     "</small>", 9);
+          tail += 9;
+
+          g_assert (len == (tail - markup));
+
+          pango_layout_set_markup (layout, markup, -1);
+          pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+
+
+          if (priv->detail_width_chars)
+            priv->min_day_width = MAX (priv->min_day_width, logical_rect.width);
+          if (priv->detail_height_rows)
+            priv->max_detail_height = MAX (priv->max_detail_height, logical_rect.height);
+        }
+
+      if (!priv->detail_width_chars || !priv->detail_height_rows)
+        for (r = 0; r < 6; r++)
+          for (c = 0; c < 7; c++)
+            {
+              const gchar *detail = gtk_calendar_get_detail (calendar, r, c);
+
+              if (detail)
+                {
+                  markup = g_strconcat ("<small>", detail, "</small>", NULL);
+                  pango_layout_set_markup (layout, markup, -1);
+
+                  if (priv->detail_width_chars)
+                    {
+                      pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
+                      pango_layout_set_width (layout, PANGO_SCALE * priv->min_day_width);
+                    }
+
+                  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+
+                  if (!priv->detail_width_chars)
+                    priv->min_day_width = MAX (priv->min_day_width, logical_rect.width);
+                  if (!priv->detail_height_rows)
+                    priv->max_detail_height = MAX (priv->max_detail_height, logical_rect.height);
+
+                  g_free (markup);
+                }
+            }
+    }
+
+  /* We add one to max_day_char_width to be able to make the marked day "bold" */
+  priv->max_day_char_width = priv->min_day_width / 2 + 1;
+
   main_width = (7 * (priv->min_day_width + (focus_padding + focus_width) * 2) + (DAY_XSEP * 6) + CALENDAR_MARGIN * 2
                + (priv->max_week_char_width
                   ? priv->max_week_char_width * 2 + (focus_padding + focus_width) * 2 + CALENDAR_XSEP * 2
@@ -1766,6 +1864,7 @@ gtk_calendar_size_request (GtkWidget        *widget,
   priv->main_h = (CALENDAR_MARGIN + calendar_margin
                          + 6 * (priv->max_day_char_ascent
                                 + priv->max_day_char_descent 
+                                 + priv->max_detail_height
                                 + 2 * (focus_padding + focus_width))
                          + DAY_YSEP * 5);
   
@@ -2199,6 +2298,14 @@ calendar_invalidate_day (GtkCalendar *calendar,
     }
 }
 
+static gboolean
+is_color_attribute (PangoAttribute *attribute,
+                    gpointer        data)
+{
+  return (attribute->klass->type == PANGO_ATTR_FOREGROUND ||
+          attribute->klass->type == PANGO_ATTR_BACKGROUND);
+}
+
 static void
 calendar_paint_day (GtkCalendar *calendar,
                    gint             row,
@@ -2208,6 +2315,7 @@ calendar_paint_day (GtkCalendar *calendar,
   GtkCalendarPrivate *priv = GTK_CALENDAR_GET_PRIVATE (calendar);
   cairo_t *cr;
   GdkColor *text_color;
+  const gchar *detail;
   gchar buffer[32];
   gint day;
   gint x_loc, y_loc;
@@ -2269,12 +2377,20 @@ calendar_paint_day (GtkCalendar *calendar,
    * too.
    */
   g_snprintf (buffer, sizeof (buffer), Q_("calendar:day:digits|%d"), day);
+
+  /* Get extra information to show, if any: */
+
+  if (priv->detail_func)
+    detail = gtk_calendar_get_detail (calendar, row, col);
+  else
+    detail = NULL;
+
   layout = gtk_widget_create_pango_layout (widget, buffer);
+  pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
   
-  x_loc = day_rect.x + day_rect.width / 2 + priv->max_day_char_width;
-  x_loc -= logical_rect.width;
-  y_loc = day_rect.y + (day_rect.height - logical_rect.height) / 2;
+  x_loc = day_rect.x + (day_rect.width - logical_rect.width) / 2;
+  y_loc = day_rect.y;
   
   gdk_cairo_set_source_color (cr, text_color);
   cairo_move_to (cr, x_loc, y_loc);
@@ -2287,6 +2403,65 @@ calendar_paint_day (GtkCalendar *calendar,
       pango_cairo_show_layout (cr, layout);
     }
 
+  y_loc += priv->max_day_char_descent;
+
+  if (priv->detail_func)
+    {
+      cairo_set_line_width (cr, 1);
+      cairo_move_to (cr, day_rect.x + 1, y_loc + 0.5);
+      cairo_line_to (cr, day_rect.x + day_rect.width - 1, y_loc + 0.5);
+      cairo_stroke (cr);
+
+      y_loc += 2;
+    }
+
+  if (detail)
+    {
+      gint i, n_lines;
+
+      gchar *markup = g_strconcat ("<small>", detail, "</small>", NULL);
+      pango_layout_set_markup (layout, markup, -1);
+      g_free (markup);
+
+      if (day == calendar->selected_day)
+        {
+          /* Stripping colors as they conflict with selection marking. */
+
+          PangoAttrList *attrs = pango_layout_get_attributes (layout);
+          PangoAttrList *colors = NULL;
+
+          if (attrs)
+            colors = pango_attr_list_filter (attrs, is_color_attribute, NULL);
+          if (colors)
+            pango_attr_list_unref (colors);
+        }
+
+      if (priv->detail_width_chars)
+        {
+          pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
+          pango_layout_set_width (layout, PANGO_SCALE * priv->min_day_width);
+        }
+
+      n_lines = pango_layout_get_line_count (layout);
+
+      if (priv->detail_height_rows)
+        n_lines = MIN (n_lines, priv->detail_height_rows);
+
+      for (i = 0; i < n_lines; ++i)
+        {
+          PangoLayoutLine *line = pango_layout_get_line_readonly (layout, i);
+          pango_layout_line_get_pixel_extents (line, NULL, &logical_rect);
+
+          x_loc  = day_rect.x + (day_rect.width - logical_rect.width) / 2;
+          y_loc += PANGO_ASCENT (logical_rect);
+
+          cairo_move_to (cr, x_loc, y_loc);
+          pango_cairo_show_layout_line (cr, line);
+
+          y_loc += PANGO_DESCENT (logical_rect);
+        }
+    }
+
   if (GTK_WIDGET_HAS_FOCUS (calendar) 
       && calendar->focus_row == row && calendar->focus_col == col)
     {